#include "./include/tlv.h"

// 在屏幕上高亮显示内容
#define BLUE "\033[34m"
#define GREEN "\033[32m"
#define YELLOW "\033[33m"
#define CYAN "\033[36m"
#define RESET "\033[0m"
#define BOLD "\033[1m"
#define GREY "\033[90m"
#define RED "\033[31m"

// 维护用户登录后的信息
client_session user_info;
// 维护客户端虚拟路径
char virtual_path[MAX_PATH] = "/";

// 借助token判断用户当前处于是否登录的状态
int is_logged_in(){
    // token为空表示用户没有登录，用户登录时才会被服务端分配一个Token
    return strlen(user_info.token)>0;
}

// 读配置文件
#define MAX_LINE_LENGTH 128

void read_config(const char *config_file, char *ip, char *port) {
    FILE *fp = fopen(config_file, "r");
    if (fp == NULL) {
        perror("Unable to open config file");
        exit(EXIT_FAILURE);
    }

    char line[MAX_LINE_LENGTH];
    while (fgets(line, sizeof(line), fp)) {
        if (strncmp(line, "SERVER_IP", 9) == 0) {
            sscanf(line, "SERVER_IP = %s", ip);
        } else if (strncmp(line, "SERVER_PORT", 11) == 0) {
            sscanf(line, "SERVER_PORT = %s", port);
        }
    }

    /* printf("ip = %s port = %s\n", ip, port); */

    fclose(fp);
}

// 建立连接
int connect_to_server(char *ip,char *port_str){
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    if(sockfd == -1){
        thread_perror("socket");
        return -1;
    }
    
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(ip);
    addr.sin_port = htons(atoi(port_str));
        
    if(connect(sockfd,(struct sockaddr*)&addr,sizeof(addr)) == -1){
        thread_perror("connect");
        close(sockfd);
        return -1;
    }
    
    return sockfd;
}

int main(int argc, char *argv[]){
    // ./client 192.168.213.130 12345
    /* ARGS_CHECK(argc,3); */
    
    read_config("/home/zhaoziloong/netdisk/client/config.cfg",user_info.ip,user_info.port);

    /* // 记录ip地址与端口号 */
    /* strncpy(user_info.ip,argv[1],sizeof(user_info.ip)); */
    /* strncpy(user_info.port,argv[2],sizeof(user_info.port)); */
    
    
    int sockfd = connect_to_server(user_info.ip,user_info.port);
    if(sockfd==-1){
        thread_perror("socket");
        return -1;
    }
    
    // 记录主线程的sockfd
    user_info.sockfd = sockfd;
    bzero(user_info.username,sizeof(user_info.username));
    
    logf("user %s established a TCP connection",user_info.username);

    trie_t cmd_dict;
    init_func(&cmd_dict); // 初始化所有命令字典，把所有支持的命令注册进去
    cmd_func_ptr_t exit_cmd_func=trie_get_func(&cmd_dict,"exit"); // 提前拿到exit命令处理指针
                                                                  // 处理fgets失败情况
    // cmd:命令关键字 arg:命令参数 cmd+line:整行输入
    char cmd[CMD_MAX],arg[ARG_MAX],cmd_line[CMD_LINE_MAX];

    long exit_flag=0; // 用于判断是否退出主循环
    
    if (!is_logged_in()) {
    // 炫彩 LOGO
        printf(BOLD GREEN
            "   ██████╗    ██╗  ██╗     ██████╗ ╗███████╗\n"
            "  ██╔═══██╗  ╚██╗██╔╝     ╚════██║ ╚██╔════╝\n"
            "  ██║   ██║   ╚███╔╝       █████╔╝ ████╗\n"
            "  ██║   ██║   ██╔██╗       ╚══██╗   █══╝\n"
            "  ╚██████╔╝  ██╔╝ ██╗    ██████╔╝  ███╗\n"
            "   ╚═════╝   ╚═╝  ╚═╝      ╚════╝ ╚══╝  \n" RESET);

        printf(   "Welcome to 0x3F\n");
        printf(   "小组成员: 王杰 王雨浩 王毓 魏一飞 郑良鹏 赵子龙 \n\n");
    }
    while(!exit_flag){
        if (!is_logged_in()) { // 检查用户是否登录
            // 未登录状态提示
            printf(BLUE "\nAvailable commands:\n" RESET);
            printf(GREEN "  login    " RESET "- Login to your account\n");
            printf(GREEN "  register " RESET "- Create new account\n");
            printf(GREEN "  exit     " RESET "- Quit the program\n\n");
        } else {
            // 已登录状态提示
            printf(BLUE "\nAvailable commands:\n" RESET);
            printf(GREEN "  cd/ls/pwd    " RESET "- Navigation\n");
            printf(GREEN "  remove       " RESET "- Delete file\n");
            printf(GREEN "  mkdir/rmdir  " RESET "- Directory management\n");
            printf(GREEN "  puts/gets    " RESET "- File transfer\n");
            printf(GREEN "  exit         " RESET "- Quit the program\n\n");
        }
    
        // 显示当前虚拟路径提示符
        if(user_info.username[0] == '\0' || (!is_logged_in())){
            printf(GREY "[off-line]: " RESET);        
            fflush(stdout); // 输出提示符

        }
        else{
            printf(GREEN "[%s@ %s] " RESET,user_info.username, virtual_path);        
            fflush(stdout); // 输出提示符
        }
        
        // 客户端这里使用select监听服务端是否关闭了sockfd
        fd_set readfds;
        FD_ZERO(&readfds);
        FD_SET(STDIN_FILENO, &readfds);
        FD_SET(sockfd, &readfds);

        int maxfd = (STDIN_FILENO > sockfd ? STDIN_FILENO : sockfd) + 1;
        int ret = select(maxfd, &readfds, NULL, NULL, NULL);
        if (ret == -1) {
            perror("select");
            break;
        }

        if (FD_ISSET(sockfd, &readfds)) {
            char buffer[1024];
            int n = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
            if (n <= 0) {
                printf(RED "\n[DISCONNECTED] Server kicked you out.\n" RESET);
                close(sockfd);
                exit(0);
            }
            buffer[n] = '\0';
            // 可选：你可以选择打印服务端发来的消息
            printf(RED "\n[Server]: %s\n" RESET, buffer);
        }

        // === 用户输入命令 ===
        if (FD_ISSET(STDIN_FILENO, &readfds)) {
            if(fgets(cmd_line,sizeof(cmd_line),stdin)==NULL){
                if(exit_cmd_func){
                    exit_cmd_func(sockfd,"");
                    printf("\n");
                }
                break;
            }
        }

        cmd[0]='\0',arg[0]='\0'; // 清空之前的命令与参数
        sscanf(cmd_line,"%s %s",cmd,arg); // 解析输入的命令和参数
#ifdef DEBUG
        printf("cmd=%s\narg=%s\n",cmd,arg);
#endif
        cmd_func_ptr_t func=trie_get_func(&cmd_dict,cmd);
        if(func!=NULL){
            exit_flag=(long)func(sockfd,arg); // 执行命令
            printf("\n");
        }else{
            printf("Invalid Command.\n");
        }
    }
    close(sockfd);
    return 0;
}

void request_exit_callback(uint32_t response_code,uint32_t length,const uint8_t *value,void *arg){
    printf(GREEN "Goodbye. Wish you happiness!\n" RESET);
    exit(EXIT_SUCCESS);
}

void *func_exit(int sockfd,const char *arg){
    logf("user %s executed command: exit",user_info.username);
    if(tlv_request(sockfd,REQUEST_EXIT,strlen(arg)+1
                   ,(const uint8_t*)arg,request_exit_callback,NULL) == -1){
        thread_perror("tlv_request");
        return NULL;
    }
    
    // 清除token，关闭定时器
    memset(user_info.token,0,sizeof(user_info.token));
    timer_delete(user_info.token_timer);

    return NULL;
}

void request_cd_callback(uint32_t response_code,uint32_t length,const uint8_t *value,void *arg){
    printf("cd: response code = %d\n",response_code);
    if(response_code == RESPONSE_OK){
        printf("Change directory successfully.\n");
        // 更新客户端虚拟路径:
        snprintf(virtual_path,sizeof(virtual_path),"%s",(char *)arg);
    }
    else{
        printf("Failed to change directory:%.*s\n",length,value);
    }
    
    free(arg);

    return;
}

void *func_cd(int sockfd,const char *arg){
    // 先登录
    if(!is_logged_in()){
        printf("please login first\n");
        return NULL;
    }
    
    logf("user %s executed command: cd",user_info.username);
    
    // 规范化路径
    char normalized[MAX_PATH];
    parse_path(virtual_path,arg,normalized);
    printf("normalized = %s\n",normalized);
    
    char *path_copy = strdup(normalized);
    if(!path_copy){
        thread_perror("strdup failed");
        return NULL;
    }
 
    char buf[TLV_VALUE_MAX_SIZE];
    sprintf(buf,"%s %s",user_info.token,normalized);

    char *token_path_copy = strdup(buf);
    if(!token_path_copy){
        thread_perror("strdup failed");
        return NULL;
    }

    // 发送客户端token+path到服务端
    if(tlv_request(sockfd,REQUEST_CD,strlen(token_path_copy)+1
                   ,(const uint8_t*)token_path_copy,request_cd_callback,path_copy) == -1){
        thread_perror("tlv_request");
        return NULL;
    }
    return NULL;
}

void *func_pwd(int sockfd,const char *arg){
    if(!is_logged_in()){
        printf("please login first\n");
        return NULL;
    }
    
    logf("user %s executed command: pwd",user_info.username);
    
    printf("%s\n",virtual_path);

    return NULL;
}

void request_ls_callback(uint32_t response_code,uint32_t length,const uint8_t *value,void *arg){
    if(response_code == RESPONSE_OK){
        printf("Directory listing:\n%.*s\n",length,value);
    }
    else{
        printf("Failed to change directory:%.*s\n",length,value);
    }
    
    return;
}

void *func_ls(int sockfd,const char *arg){
    if(!is_logged_in()){
        printf("please login first\n");
        return NULL;
    }

    logf("user %s executed command: ls",user_info.username);
    
    // 规范化路径
    char normalized[MAX_PATH];
    parse_path(virtual_path,arg,normalized);

    char buf[TLV_VALUE_MAX_SIZE];
    sprintf(buf,"%s %s",user_info.token,normalized);
    
    printf("ls send path %s\n",normalized);

    char *token_path_copy = strdup(buf);
    if(!token_path_copy){
        thread_perror("strdup failed");
        return NULL;
    }

    if(tlv_request(sockfd,REQUEST_LS,strlen(token_path_copy)+1
                   ,(const uint8_t*)token_path_copy,request_ls_callback,NULL) == -1){
        thread_perror("tlv_request");
        return NULL;
    }
    return NULL;
}

void request_mkdir_callback(uint32_t response_code,uint32_t length,const uint8_t *value,void *arg){
    if(response_code == RESPONSE_OK){
        printf("directory was created successfully\n");
    }
    else{
        printf("Failed to create the directory\n");
    }
    
    return;
}

void *func_mkdir(int sockfd,const char *arg){
    if(!is_logged_in()){
        printf("please login first\n");
        return NULL;
    }
    
    // 规范化路径
    char normalized[MAX_PATH];
    parse_path(virtual_path,arg,normalized);
    
    logf("user %s executed command: mkdir %s",user_info.username,normalized);

    char buf[TLV_VALUE_MAX_SIZE];
    sprintf(buf,"%s %s",user_info.token,normalized);

    char *token_path_copy = strdup(buf);
    if(!token_path_copy){
        thread_perror("strdup failed");
        return NULL;
    }

    if(tlv_request(sockfd,REQUEST_MKDIR,strlen(token_path_copy)+1
                   ,(const uint8_t*)token_path_copy,request_mkdir_callback,NULL) == -1){
        thread_perror("tlv_request");
        return NULL;
    }
    return NULL;
}

void request_rmdir_callback(uint32_t response_code,uint32_t length,const uint8_t *value,void *arg){
    if(response_code == RESPONSE_OK){
        printf("The directory deletion was successful.\n");
    }
    else{
        printf("Directory deletion failed.\n");
    }
    
    return;
}

void *func_rmdir(int sockfd,const char *arg){
    if(!is_logged_in()){
        printf("please login first\n");
        return NULL;
    }

    // 规范化路径
    char normalized[MAX_PATH];
    parse_path(virtual_path,arg,normalized);
    
    char buf[TLV_VALUE_MAX_SIZE];
    sprintf(buf,"%s %s",user_info.token,normalized);

    char *token_path_copy = strdup(buf);
    if(!token_path_copy){
        thread_perror("strdup failed");
        return NULL;
    }
    
    logf("user %s executed command: rmdir %s",user_info.username,normalized);

    if(tlv_request(sockfd,REQUEST_RMDIR,strlen(token_path_copy)+1
                   ,(const uint8_t*)token_path_copy,request_rmdir_callback,NULL) == -1){
        thread_perror("tlv_request");
        return NULL;
    }
    return NULL;
}

void request_remove_callback(uint32_t response_code,uint32_t length,const uint8_t *value,void *arg){
    if(response_code == RESPONSE_OK){
        printf("The directory remove was successful.\n");
    }
    else{
        printf("Directory remove failed.\n");
    }
    
    return;
}

void *func_remove(int sockfd,const char *arg){
    if(!is_logged_in()){
        printf("please login first\n");
        return NULL;
    }

    logf("User %s executed command: remove %s",user_info.username,arg);
    
    // 规范化路径
    char normalized[MAX_PATH];
    parse_path(virtual_path,arg,normalized);

    char buf[TLV_VALUE_MAX_SIZE];
    sprintf(buf,"%s %s",user_info.token,normalized);
    
    printf("remove_path = %s\n",normalized);

    char *token_file_copy = strdup(buf);
    if(!token_file_copy){
        thread_perror("strdup failed");
        return NULL;
    }

    if(tlv_request(sockfd,REQUEST_REMOVE,strlen(token_file_copy)+1
                   ,(const uint8_t*)token_file_copy,request_remove_callback,NULL) == -1){
        thread_perror("tlv_request");
        return NULL;
    }
    
    return NULL;
}

// 对文件内容进行sha1哈希值计算
int sha1_file(const char* filename, char* sha1str) {
    unsigned char buf[4096];
    unsigned char hash[EVP_MAX_MD_SIZE];
    unsigned int hash_len = 0;

    EVP_MD_CTX* ctx = EVP_MD_CTX_new();
    if (!ctx) return -1;

    const EVP_MD* md = EVP_sha1();
    EVP_DigestInit_ex(ctx, md, NULL);

    int fd = open(filename, O_RDONLY);
    if (fd < 0) {
        perror("open");
        EVP_MD_CTX_free(ctx);
        return -1;
    }

    ssize_t len;
    while ((len = read(fd, buf, sizeof(buf))) > 0) {
        EVP_DigestUpdate(ctx, buf, len);
    }

    close(fd);
    EVP_DigestFinal_ex(ctx, hash, &hash_len);
    EVP_MD_CTX_free(ctx);

    // Convert to hex string
    for (unsigned int i = 0; i < hash_len; i++) {
        sprintf(sha1str + i * 2, "%02x", hash[i]);
    }
    sha1str[hash_len * 2] = '\0';

    return 0;
}

// 子线程上传文件
void *upload_file_thread(void *arg){
    thread_args_t *args = (thread_args_t *)arg;
    // 子线程建立连接
    int sockfd = connect_to_server(args->ip,args->port);
    if(sockfd == -1){
        thread_perror("connect_to_server");
        free(arg);
        return NULL;
    }
    
    printf("The child thread connection was successful.\n");

    char buf[TLV_VALUE_MAX_SIZE];
    snprintf(buf,sizeof(buf),"%s",args->sha1);
    if (tlv_request(sockfd, REQUEST_PUTS,strlen(buf)+1,(const uint8_t *)buf, NULL, NULL) == -1) {
        thread_perror("tlv_request");
        return NULL;
    }
    else{
        printf("PUTS command send successful.\n");
    }

    // 子线程真正执行文件上传动作
    if(send_file(sockfd,args->filename) != 0){
        printf("Thread upload failed: %s:%s\n",args->ip,args->port);
    }
    else{
        printf("Thread upload successful: %s:%s\n",args->ip,args->port);
    }

    close(sockfd);
    free(arg); // 释放参数
    return NULL;
}

void request_puts_callback(uint32_t response_code,uint32_t length,const uint8_t *value,void *arg){
    const char *filename = (char *)arg;
    
    if(response_code == RESPONSE_FILE_EXIST){
        printf("The file was uploaded successfully.\n");
    }
    else if(response_code == RESPONSE_OK){
        printf("value = %s\n",(char *)value);
        // value 格式"IP PORT对"
        char ip[64] = {0},port[16] = {0};
        int thread_count = 0;
        
        // 动态解析IP PORT对
        char *copy = strdup((const char *)value);
        char *token = strtok(copy," ");
        if(!token){
            printf("Invaid response: no thread count\n");
            free(copy);
            return;
        }
        thread_count = atoi(token);
        
        // 提取ip和port对
        char *ips_ports_tokens[128]; // 最多读取128对
        int count = 0;

        while((token = strtok(NULL," "))&& count < 2*thread_count){
            ips_ports_tokens[count++] = token;
        }
                
        if(count != 2 * thread_count){
            printf("Expected %d IP:PORT pairs, but got %d items.\n", thread_count, count);
            free(copy);
            free(arg);
            return;
        }

        /* printf("Upload thread count = %d\n",thread_count); */
        for(int i=0;i<count;i+=2){
            printf("Thread %d: IP = %s,Port = %s\n",i/2,ips_ports_tokens[i],ips_ports_tokens[i+1]);
        }

        for(int i=0;i<thread_count;i++){
            snprintf(ip,sizeof(ip),"%s",ips_ports_tokens[i * 2]);
            snprintf(port,sizeof(port),"%s",ips_ports_tokens[i*2 + 1]);
            // 多线程线程需要维护的东西
            thread_args_t *args = (thread_args_t *)malloc(sizeof(thread_args_t));
            snprintf(args->ip,sizeof(args->ip),"%s",ip);
            snprintf(args->port,sizeof(args->port),"%s",port);
            snprintf(args->token,sizeof(args->token),"%s",user_info.token);
            snprintf(args->sha1,sizeof(args->sha1),"%s",user_info.sha1);
            snprintf(args->path,sizeof(args->path),"%s",virtual_path);
            snprintf(args->filename,sizeof(args->filename),"%s",filename);
            

            pthread_t tid;
            if(pthread_create(&tid,NULL,upload_file_thread,args) != 0){
                thread_perror("pthread_create");
                logf("ip %s port %s pthread_create failed!",user_info.ip,user_info.port);
                free(args);
            }
            else{
                pthread_detach(tid);
            }
        }        
        logf("file %s upload successfully.",filename);
        
    }
    else{
        printf("upload failed.\n");
        logf("file %s upload failed.",filename);
    } 
    // 最终向代理服发token + sha1 + path + filename + filesize
    char result_buf[TLV_VALUE_MAX_SIZE];
    snprintf(result_buf,sizeof(result_buf),"%s %s %s %s %d",user_info.token,user_info.sha1,virtual_path,filename,user_info.filesize);
    if (tlv_request(user_info.sockfd, REQUEST_FILE_PUTS_RESULT, strlen(result_buf) + 1
                        ,(const uint8_t *)result_buf,NULL,NULL ) == -1) {
            thread_perror("tlv_request");
            return;
    }

        
    free(arg);
    return;
}

// 仅发请求，不进行上传
void *func_puts(int sockfd,const char *arg){
    if(!is_logged_in()){
        printf("please login first\n");
        return NULL;
    }
    
    logf("user %s expected command: puts %s",user_info.username,arg);
    
    user_info.flag = -1;// 初始时为-1，当为0时表示上传成功
    
    struct stat stat_buf;
    if(stat(arg,&stat_buf) == -1){
        thread_perror("stat");
    }
    else{
        // 记录文件的大小
        user_info.filesize = stat_buf.st_size;
    }

    // 计算文件的sha1值
    char sha1str[41] = {0};
    if(sha1_file(arg,sha1str) != 0){
        thread_perror("sha1_file");
        return NULL;
    }
    // 记录sha1值，便于回调
    snprintf(user_info.sha1,sizeof(user_info.sha1),"%s",sha1str);
    
    /* printf("send sha1: %s\n",user_info.sha1); */

    // 发送请求到服务端获取分发信息 buf = token + sha1 + path + filename
    char buf[TLV_VALUE_MAX_SIZE];
    snprintf(buf, sizeof(buf), "%s %s", user_info.token, sha1str);
    if (tlv_request(sockfd, REQUEST_PUTS, strlen(buf) + 1
                    ,(const uint8_t *)buf, request_puts_callback, strdup(arg)) == -1) {
        thread_perror("tlv_request");
        return NULL;
    } 

    return NULL;
}

void *download_file_thread(void *arg){
    thread_args_t *args = (thread_args_t *)arg;
    
    int sockfd = connect_to_server(args->ip,args->port);
    if(sockfd == -1){
        thread_perror("connect_to_server");
        free(arg);
        return NULL;
    }
    
    printf("I am thread ip: %s port: %s\n",args->ip,args->port);

    if(tlv_request(sockfd,REQUEST_GETS,strlen(args->sha1)+1
                   ,(const uint8_t *)args->sha1,NULL,NULL) == -1){
        thread_perror("tlv_request");
        return NULL;
    }
    
    // 给下载服要上传sha1值
    if(recv_file_fragment(sockfd,args->filename,args->begin,args->size) == -1){
        thread_perror("recv_file_fragment");
        printf("download failed.\n");
    }
    else{
        printf("download successfully\n"); 
    }
    
    free(arg);
    return NULL;
}

void request_gets_callback(uint32_t response_code, uint32_t length, const uint8_t *value, void *arg) {
    char *filename = (char *)arg;

    printf("puts: response code = %d\n", response_code);
    if (response_code == RESPONSE_FILE_NOT_EXIST) {
        printf("There is no such file.\n");
        /* free(arg); */
        return;
    }

    if (response_code != RESPONSE_OK) {
        printf("download failed.\n");
        /* free(arg); */
        return;
    }

    printf("value = %s\n", (char *)value);
    char *copy = strdup((const char *)value);
    if (!copy) {
        thread_perror("strdup");
        free(arg);
        return;
    }

    /* 解析sha1和thread_count */
    char *p = copy;
    char sha1[41] = {0};
    int thread_count = 0;
    int offset = 0;

    if (sscanf(p, "%40s %d%n", sha1, &thread_count, &offset) != 2) {
        printf("Invalid response: expected sha1 and thread count\n");
        return;
    }

    strncpy(user_info.sha1, sha1, sizeof(user_info.sha1)-1);
    p += offset;

    /* 创建下载线程 */
    for (int i = 0; i < thread_count; i++) {
        char ip[64] = {0};
        char port[16] = {0};
        int begin = 0, size = 0;

        if (sscanf(p, " %63s %15s %d %d%n", ip, port, &begin, &size, &offset) != 4) {
            printf("Invalid response: could not parse ip/port/begin/end for thread %d\n", i);
            break;  // 不再继续创建线程但会执行后续清理
        }
        /* printf("ip %s port %s begin %d end %d\n", ip, port, begin, size); */
        p += offset;

        thread_args_t *args = (thread_args_t *)malloc(sizeof(thread_args_t));
        if (!args) {
            thread_perror("malloc");
            continue;
        }

        strncpy(args->ip, ip, sizeof(args->ip)-1);
        strncpy(args->port, port, sizeof(args->port)-1);
        args->begin = begin;
        args->size = size;
        strncpy(args->token, user_info.token, sizeof(args->token)-1);
        strncpy(args->sha1, user_info.sha1, sizeof(args->sha1)-1);
        strncpy(args->path, virtual_path, sizeof(args->path)-1);
        strncpy(args->filename, filename, sizeof(args->filename)-1);

        pthread_t tid;
        if (pthread_create(&tid, NULL, download_file_thread, args) != 0) {
            thread_perror("pthread_create");
        } else {
            pthread_detach(tid);
        }
    }

    return;
}

void *func_gets(int sockfd,const char *arg){
    if(!is_logged_in()){
        printf("please login first\n");
        return NULL;
    }
    
    logf("user %s executed command: gets %s",user_info.username,arg);
    
    char buf[TLV_VALUE_MAX_SIZE];
    bzero(buf,sizeof(buf));
    sprintf(buf,"%s %s %s",user_info.token,virtual_path,(char *)arg);
 
    // 客户端给代理服发送Token + path + filename
    if(tlv_request(sockfd,REQUEST_GETS,strlen(buf)+1
                   ,(const uint8_t*)buf,request_gets_callback,(char *)arg) == -1){
        thread_perror("tlv_request");
        return NULL;
    }
    return NULL;
}

// 从终端安全读取密码，用*代替输入的内容
void get_password(char *password, size_t size) {
    struct termios oldt, newt; // 保存和设置终端属性
    tcgetattr(STDIN_FILENO, &oldt); // 获取当前终端设置(oldt),复制一份到newt,以便修改后设置
    newt = oldt;

    newt.c_lflag &= ~(ECHO | ICANON); // 关闭回显和规范模式（逐字符读取）
    tcsetattr(STDIN_FILENO, TCSANOW, &newt); // 立即生效新的终端设置(关闭了回显)

    printf("[password]: ");
    fflush(stdout);

    size_t idx = 0;
    while (idx < size - 1) {
        char ch;
        if (read(STDIN_FILENO, &ch, 1) != 1) break;

        if (ch == '\n' || ch == '\r') {
            break;
        } else if (ch == 127 || ch == 8) { // 处理退格（兼容DEL和BS）
            if (idx > 0) {
                idx--;
                printf("\b \b"); // 删除一个*
                fflush(stdout);
            }
        } else {
            password[idx++] = ch;
            printf("*");
            fflush(stdout);
        }
    }
    password[idx] = '\0';

    tcsetattr(STDIN_FILENO, TCSANOW, &oldt); // 恢复终端设置
    printf("\n");
}

void request_register_result_callback(uint32_t response_code,uint32_t length,const uint8_t *value,void *arg){
    if(response_code == RESPONSE_USERNAME_IS_EXIST){
        printf("The user already exists. Please log in directly\n");
    }
    if(value){
        printf("%.*s\n",length,value);
    }
    return;
}

void request_register_callback(uint32_t response_code,uint32_t length,const uint8_t *value,void *arg){
    if(response_code != RESPONSE_OK){
        printf("get salt failed\n");
        return;
    }
    
    int sockfd = ((user_info_ctx_t *)arg)->sockfd;
    char *username = ((user_info_ctx_t*)arg)->username;
    char *password = ((user_info_ctx_t*)arg)->password;
    
    // 客户端接收服务端发来的盐值
    const char *salt = (const char *)value;
    if(salt == NULL){
        printf("salt error!\n");
        return;
    }
    
    // 加密(线程安全函数)
    struct crypt_data pwd_crypt_data;
    pwd_crypt_data.initialized = '\0';
    
    char *computed_hash = crypt_r(password,salt,&pwd_crypt_data);
    if(!computed_hash){
        thread_perror("crypt");
        return;
    }

    // 将客户端生成的密文发给服务端
    char buf[TLV_VALUE_MAX_SIZE];
    sprintf(buf,"%s %s",username,computed_hash);
    printf("buf = %s\n",buf);

    // 发送密文
    logf("user %s send username and salt to server",user_info.username);
    if(tlv_request(sockfd,REQUEST_REGISTER,strlen(buf)+1
                   ,(const uint8_t*)buf,request_register_result_callback,NULL) == -1){
        thread_perror("tlv_request");
    }
    
    free(((user_info_ctx_t *)arg)->username);
    free(((user_info_ctx_t *)arg)->password);
    free(arg);

    return;
}

// 注册
void *func_register(int sockfd,const char *arg){ 
    // 输入用户名
    printf("[username]: ");
    char username[31];
    fflush(stdout);
    if(fgets(username,sizeof(username),stdin) == NULL){
        return NULL;
    }
    username[strcspn(username,"\n")] = '\0';

    logf("user %s executed command: register",user_info.username);
    
    // 从终端获取密码
    char password[TLV_VALUE_MAX_SIZE];
    get_password(password,sizeof(password));

    user_info_ctx_t *register_info = (user_info_ctx_t *)malloc(sizeof(user_info_ctx_t));
    register_info->sockfd = sockfd;
    register_info->username = strdup(username);
    register_info->password = strdup(password);
    
    // 发送用户名获取盐值
    logf("user %s send salt to server",user_info.username);
    if(tlv_request(sockfd,REQUEST_GET_SALT,sizeof(username)+1
                   ,(uint8_t*)&username,request_register_callback,register_info) == -1){
        thread_perror("tlv_request");
        return NULL;
    }
    
    return NULL;
}

void token_expired_handler(union sigval arg){
    fprintf(stderr,"[ERROR] Your session has expired. Please log in again.\n");
    logf("user %s session has expired",user_info.username);
    // 到期后清空token信息
    memset(&user_info.token,0,sizeof(user_info.token));
}

//  启动一个30分钟的定时器
int start_token_timer(){
    struct sigevent sev;
    struct itimerspec its;

    // 设置定时器到期执行的函数
    memset(&sev,0,sizeof(struct sigevent));
    sev.sigev_notify = SIGEV_THREAD;
    sev.sigev_notify_function = token_expired_handler;
    sev.sigev_value.sival_ptr = &user_info.token_timer;
    
    if(timer_create(CLOCK_REALTIME,&sev,&user_info.token_timer) == -1){
        thread_perror("timer_creat");
        return -1;
    }
    
    // 设置定时器:1800秒触发一次
    its.it_value.tv_sec = TOKEN_LIFETIME_SECONDS;
    its.it_value.tv_nsec = 0;
    its.it_interval.tv_sec = 0;
    its.it_interval.tv_nsec = 0;
    
    if(timer_settime(user_info.token_timer,0,&its,NULL) == -1){
        thread_perror("timer_settime");
        return -1;
    }

    /* printf("Token timer started for 30 minutes.\n"); */

    return 0;
}


void request_login_result_callback(uint32_t response_code,uint32_t length,const uint8_t *value,void *arg){
    if(response_code == RESPONSE_USERNAME_NOT_EXIST){
        printf("username is not exist!\n");
        logf("user %s input password failed",user_info.username);
        return;
    }

    if(response_code == RESPONSE_PASSWORD_WRONG){
        printf("password wrong\n");
        logf("user %s input password failed",user_info.username);
        return;
    }
   
    if(response_code == RESPONSE_OK){
        printf(GREEN "Welcome! Nice to meet you!\n" RESET);
        logf("user %s login success",user_info.username);
        size_t copy_len = (length<sizeof(user_info.token)-1)?length:sizeof(user_info.token)-1;
        // memcpy第二个类型是const void *,接收任何类型的指针
        memcpy(user_info.token,value,copy_len);
        user_info.token[copy_len] = '\0';
        logf("user %s get token",user_info.username);

        // 启动一个30min的定时器
        if(start_token_timer() != 0){
            fprintf(stderr,"Failed to start timer.\n");
            return;
        }
    }
        
    return;
}

void request_login_callback(uint32_t response_code,uint32_t length,const uint8_t *value,void *arg){
    if(response_code == RESPONSE_ERROR_REQUEST){
        printf("login request failed\n");
        logf("user %s login falied",user_info.username);
        return;
    }

    int sockfd = ((user_info_ctx_t *)arg)->sockfd;
    char *username = ((user_info_ctx_t*)arg)->username;
    char *password = ((user_info_ctx_t*)arg)->password;
    
    // 客户端接收服务端发来的盐值
    const char *salt = (const char *)value;
    if(salt == NULL){
        printf("salt error!\n");
        return;
    }
    
    // 加密(线程安全函数)
    struct crypt_data pwd_crypt_data;
    pwd_crypt_data.initialized = '\0';
    char *computed_hash = crypt_r(password,salt,&pwd_crypt_data);
    if(!computed_hash){
        thread_perror("crypt");
        return;
    }
    
    // buf里存储用户名+密文
    char buf[TLV_VALUE_MAX_SIZE];
    sprintf(buf,"%s %s",username,computed_hash);

    // 发送用户名+密文
    if(tlv_request(sockfd,REQUEST_LOGIN,strlen(buf)+1
                   ,(const uint8_t*)buf,request_login_result_callback,NULL) == -1){
        thread_perror("tlv_request");
        return;
    }

    free(((user_info_ctx_t*)arg)->username);
    free(((user_info_ctx_t*)arg)->password);
    free(arg);

    return;
}

// 登录
void *func_login(int sockfd,const char *arg){
    // 输入用户名
    printf("[username]: ");
    char username[31];
    fflush(stdout);
    if(fgets(username,sizeof(username),stdin) == NULL){
        return NULL;
    }
    username[strcspn(username,"\n")] = '\0';
    
    // 记录用户名
    snprintf(user_info.username,sizeof(user_info.username),"%s",username);

    logf("user %s execute command: login",user_info.username);

    // 从终端获取密码
    char password[TLV_VALUE_MAX_SIZE];
    get_password(password,sizeof(password));
    
    // 暂存用户信息
    user_info_ctx_t *login_info = (user_info_ctx_t *)malloc(sizeof(user_info_ctx_t));
    login_info->sockfd = sockfd;
    login_info->username = strdup(username);
    login_info->password = strdup(password);
    
    // 发送用户名获取盐值
    if(tlv_request(sockfd,REQUEST_GET_SALT,strlen(username)+1
                   ,(const uint8_t*)username,request_login_callback,login_info) == -1){
        thread_perror("tlv_request");
        return NULL;
    }
    
    return NULL;
}


void request_deregister_callback(uint32_t response_code,uint32_t length,const uint8_t *value,void *arg){
    printf("deregister response code = %d\n",response_code);
    if(response_code != RESPONSE_OK){
        printf("deregister failed\n");
        return;
    }
    else{
        printf("user logout was successful.\n");

        logf("user %s deregister successful",user_info.username);
        // 注销后要清空token
        memset(user_info.token,0,sizeof(user_info.token));
        printf("You have been logged out.\n");
        
        return;
    }    
}

// 注销
void *func_deregister(int sockfd,const char *arg){ 
    // 注销前一定要先登录
    if(!is_logged_in()){
        printf("please login first\n");
        return NULL;
    }

    logf("user %s execute command: deregister",user_info.username);
    
    // 客户端发送注销请求，发送token
    if(tlv_request(sockfd,REQUEST_DEREGISTER,sizeof(user_info.token)
                   ,(uint8_t*)&user_info.token,request_deregister_callback,NULL) == -1){
        thread_perror("tlv_request");
        return NULL;
    }

    return NULL;
}

void init_func(trie_t *cmd_dict){
    bzero(cmd_dict,sizeof(trie_t));
    trie_insert(cmd_dict,"exit",func_exit);
    trie_insert(cmd_dict,"cd",func_cd);
    trie_insert(cmd_dict,"pwd",func_pwd);
    trie_insert(cmd_dict,"ls",func_ls);
    trie_insert(cmd_dict,"mkdir",func_mkdir);
    trie_insert(cmd_dict,"rmdir",func_rmdir);
    trie_insert(cmd_dict,"remove",func_remove);
    trie_insert(cmd_dict,"puts",func_puts);
    trie_insert(cmd_dict, "gets", func_gets);
    trie_insert(cmd_dict,"register",func_register);
    trie_insert(cmd_dict,"login",func_login);
    trie_insert(cmd_dict,"deregister",func_deregister);    
}
